
#pragma once

#define NULL_COLUMN                 -1
#define NULL_ITEM                   -1
#define NULL_SUBITEM                -1
#define ITEM_HEIGHT_MARGIN          6
#define ITEM_WIDTH_MARGIN           20
#define ITEM_SCROLL_OFFSET          5
#define DRAG_HEADER_OFFSET          4
#define DRAG_ITEM_OFFSET            3
#define ITEM_EDIT_MARGIN            5
#define TOOLTIP_TOOL_ID             1000
#define RESIZE_COLUMN_TIMER         1001
#define RESIZE_COLUMN_PERIOD        20
#define ITEM_VISIBLE_TIMER          1002
#define ITEM_VISIBLE_PERIOD         250
#define SEARCH_PERIOD               800
#define ITEM_AUTOSCROLL_TIMER       1003
#define ITEM_SCROLL_TIMER           1004
#define ITEM_SCROLL_PERIOD          20
#define ITEM_SCROLL_UNIT_MAX        8
#define ITEM_SCROLL_UNIT_MIN        4

#define ITEM_FORMAT_NONE            0
#define ITEM_FORMAT_EDIT            1
#define ITEM_FORMAT_DATETIME        2
#define ITEM_FORMAT_COMBO           3
#define ITEM_FORMAT_CHECKBOX        4
#define ITEM_FORMAT_CHECKBOX_3STATE 5
#define ITEM_FORMAT_HYPERLINK       6
#define ITEM_FORMAT_PROGRESS        7
#define ITEM_FORMAT_CUSTOM          8

#define ITEM_FLAGS_NONE             0x0000
#define ITEM_FLAGS_LEFT             0x0001
#define ITEM_FLAGS_RIGHT            0x0002
#define ITEM_FLAGS_CENTRE           0x0004
#define ITEM_FLAGS_READ_ONLY        0x0008
#define ITEM_FLAGS_EDIT_UPPER       0x0010
#define ITEM_FLAGS_EDIT_NUMBER      0x0020
#define ITEM_FLAGS_EDIT_FLOAT       0x0040
#define ITEM_FLAGS_EDIT_NEGATIVE    0x0080
#define ITEM_FLAGS_EDIT_OPERATOR    0x0100
#define ITEM_FLAGS_COMBO_EDIT       0x0200
#define ITEM_FLAGS_DATE_ONLY        0x0400
#define ITEM_FLAGS_TIME_ONLY        0x0800
#define ITEM_FLAGS_DATETIME_NONE    0x1000
#define ITEM_FLAGS_PROGRESS_SOLID   0x2000

#define ITEM_IMAGE_NONE             -1
#define ITEM_IMAGE_DOWN             0
#define ITEM_IMAGE_UP               1
#define ITEM_IMAGE_CHECK_OFF        2
#define ITEM_IMAGE_CHECK_ON         3
#define ITEM_IMAGE_3STATE_UNDEF     ITEM_IMAGE_CHECK_OFF
#define ITEM_IMAGE_3STATE_ON        4
#define ITEM_IMAGE_3STATE_OFF       5
#define ITEM_IMAGE_LOCK             6
#define ITEM_IMAGE_ATTACHMENT       7
#define ITEM_IMAGE_3STATE           8
#define ITEM_IMAGE_CHECKBOX         9

#define HITTEST_FLAG_NONE           0x0000
#define HITTEST_FLAG_HEADER_DIVIDER 0x0001
#define HITTEST_FLAG_HEADER_LEFT    0x0002
#define HITTEST_FLAG_HEADER_RIGHT   0x0004

#define LCN_FIRST                   ( 0U - 1500U )
#define LCN_LAST                    ( 0U - 1600U )

#define LCN_SELECTED                ( LCN_FIRST - 1 )
#define LCN_LEFTCLICK               ( LCN_FIRST - 2 )
#define LCN_RIGHTCLICK              ( LCN_FIRST - 3 )
#define LCN_DBLCLICK                ( LCN_FIRST - 4 )
#define LCN_ENDEDIT                 ( LCN_FIRST - 5 )
#define LCN_MODIFIED                ( LCN_FIRST - 6 )
#define LCN_HYPERLINK               ( LCN_FIRST - 7 )

struct CListNotify {
    NMHDR m_hdrNotify;
    int m_nItem;
    int m_nSubItem;
    TCHAR m_nExitChar;
    LPCTSTR m_lpszItemText;
    LPSYSTEMTIME m_lpItemDate;
};

template <class T, class TEqual = CSimpleArrayEqualHelper< T > >
class CListArray : public CSimpleArray< T, TEqual >
{
public:
    void Reverse()
    {
        reverse(m_aT, m_aT + m_nSize);
    }

    void Sort()
    {
        sort(m_aT, m_aT + m_nSize);
    }

    template< class Pred > inline
    void Sort(Pred Compare)
    {
        sort(m_aT, m_aT + m_nSize, Compare);
    }

    BOOL IsEmpty()
    {
        return (GetSize() == 0);
    }

    BOOL InsertAt(int nIndex, const T& t)
    {
        if (nIndex < 0)
            return FALSE;

        if (nIndex >= m_nSize)
            return (Add(t) != -1);

        if (m_nSize == m_nAllocSize) {
            int nNewAllocSize = (m_nAllocSize == 0) ? 1 : (m_nSize * 2);
            T* aT = (T*)realloc(m_aT, nNewAllocSize * sizeof(T));

            if (aT == NULL)
                return FALSE;

            m_nAllocSize = nNewAllocSize;
            m_aT = aT;
        }

        MoveMemory((LPVOID)(m_aT + nIndex + 1), (LPVOID)(m_aT + nIndex), (m_nSize - nIndex) * sizeof(T));
        InternalSetAtIndex(nIndex, t);
        m_nSize++;
        return TRUE;
    }
};
